/* 

my_thai_utils - a library of MySQL UDF functions for handling Thai language
Copyright (C) 2009 Thawatchai Piyawat
email: thawatchai@usablelabs.org

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

*/

/*
 * dependencies: MySQL, ICU
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mysql.h>

#include <unicode/uchar.h>
#include <unicode/brkiter.h>
#include <unicode/unistr.h>

/* function declarations ---------------------------------------------------- */

#ifdef	__cplusplus
extern "C" {
#endif

	/* thai_space_split */
	my_bool thai_space_split_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
	char *thai_space_split(UDF_INIT *initid, UDF_ARGS *args,
			char *result, unsigned long *length, char *is_null, char *error);
	void thai_space_split_deinit(UDF_INIT *initid);

#ifdef	__cplusplus
}
#endif

/* function definitions ----------------------------------------------------- */

void strip_html(UnicodeString *src, UnicodeString *target)
{
	int32_t src_length = src->length();
	const UnicodeString csrc = src->unescape();

	UChar current_ch, open_ch = '<', close_ch = '>';
	int pivot = 0;
	for (int i=0; i<src_length; i++)
	{
		current_ch = src->charAt(i);
		if (current_ch == open_ch)
		{
			target->append(csrc, pivot, i - pivot);
		}
		else if (current_ch == close_ch)
		{
			pivot = i + 1;
		}
		if (i == src_length - 1)
		{
			target->append(csrc, pivot, i - pivot + 1);
		}
	}
}

/*
 * thai_space_split
 */

my_bool thai_space_split_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
	/* sanity check */
	initid->max_length = initid->max_length * 2;

	if (args->arg_count != 1)
	{
		strcpy(message, "THAI_SPACE_SPLIT() requires one argument.");
		return 1;
	}
	args->arg_type[0] = STRING_RESULT;

	/* allocate memory for the return value */
	initid->ptr = (char*) calloc(initid->max_length * 2, sizeof(char));
	if (initid->ptr == NULL)
	{
		strcpy(message, "THAI_SPACE_SPLIT() cannot allocate memory.");
		return 1;
	}

	return 0;
}

char *thai_space_split(UDF_INIT *initid, UDF_ARGS *args,
		char *result, unsigned long *length, char *is_null, char *error)
{
	/* return NULL if NULL */
	if (args->args[0] == NULL) { *is_null = 1; return NULL; }

	/* split and insert space using ICU routines */
	UErrorCode status = U_ZERO_ERROR;

	UnicodeString *raw_arg = new UnicodeString(args->args[0], args->lengths[0]);
	UnicodeString *arg = new UnicodeString();

	strip_html(raw_arg, arg);

	const UnicodeString carg = arg->unescape();
	int32_t carg_length = arg->length();

	UnicodeString *out = new UnicodeString();

	BreakIterator *bi = BreakIterator::createWordInstance(Locale("th"), status);
	bi->setText(carg);

	UChar space = ' ';
	int32_t prev, p = bi->first();
	while (p != BreakIterator::DONE)
	{
		prev = p;
		p = bi->next();
		if (p != BreakIterator::DONE)
		{
			out->append(carg, prev, p - prev);
			out->append((p < (carg_length-1)) ? space : (UChar) NULL);
		}
	}
	delete bi;

	out->extract(0, out->length(), initid->ptr);
	delete out;

	delete arg;
	delete raw_arg;

	/* return result */
	*length = strlen(initid->ptr);
	return initid->ptr;
}

void thai_space_split_deinit(UDF_INIT *initid)
{
	free(initid->ptr);
}

